#include <iostream>

#include <conio.h>
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <Windows.h>

#pragma comment(lib, "ws2_32")

using namespace std;
using std::cout;

int main(int argc, char **argv)
{
    if (argc < 2)
    {
        cout << "spawning new process" << endl;

        // wait for injection
        Sleep(1 * 500);

        {
            STARTUPINFO si = {};
            PROCESS_INFORMATION pi = {};
            si.cb = sizeof(STARTUPINFO);
            ::CreateProcess(argv[0], "-testcallback 127.0.0.1:8010", nullptr, nullptr, false, CREATE_NEW_CONSOLE, nullptr, nullptr, &si, &pi);
        }
        {
            STARTUPINFO si = {};
            PROCESS_INFORMATION pi = {};
            si.cb = sizeof(STARTUPINFO);
            ::CreateProcess(argv[0], "-listen 127.0.0.1:8011", nullptr, nullptr, false, CREATE_NEW_CONSOLE, nullptr, nullptr, &si, &pi);
        }
    }
    else if (strcmp(argv[0], "-testcallback") == 0)
    {
        cout << "sending back test information" << endl;
        auto host = argv[1];

        WSADATA wsaData;
        WSAStartup(0x201, &wsaData);

        SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

        SOCKADDR addr;
        int addrlen = sizeof(SOCKADDR);
        WSAStringToAddress(host, AF_INET, nullptr, &addr, &addrlen);

        cout << "connecting ..." << endl;
        int retv = connect(s, &addr, addrlen);
        if (retv == 0)
        {
            cout << "connected !" << endl;
            char str[] = "test";

            cout << "sending : " << str << endl;
            send(s, str, sizeof(str), 0);
            
            Sleep(1000);
            closesocket(s);
        }
        cout << "closed" << endl;
    }
    else if (strcmp(argv[0], "-listen") == 0)
    {
        cout << "startup a host" << endl;
        auto host = argv[1];

        WSADATA wsaData;
        WSAStartup(0x201, &wsaData);

        SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

        SOCKADDR addr;
        int addrlen = sizeof(addr);
        WSAStringToAddress(host, AF_INET, nullptr, &addr, &addrlen);
        
        bind(s, &addr, addrlen);

        listen(s, 1);

        cout << "listening ..." << endl;
        sockaddr_in inaddr;
        int inaddrlen = sizeof(sockaddr_in);
        SOCKET c = accept(s, (SOCKADDR *)&inaddr, &inaddrlen);
        cout << "new connection!" << endl;

        for (int i = 0; i < 2 ; i++)
        {
            cout << "recving ..." << endl;
            char buf[1024];

            int nrecv = recv(c, buf, 1024, 0);
            if (nrecv > 0)
            {
                cout << "sending back ..." << endl;
                send(c, buf, nrecv, 0);
            }
        }

        Sleep(1000);
        closesocket(s);
        closesocket(c);
        cout << "closed" << endl;
    }
    else
    {
        cout << "nothing to do" << endl;
        cout << "argv[1] : " << argv[1] << endl;
    }
    // wait for proment
    Sleep(1 * 500);
}